package SSF.App.DDoS;

import SSF.OS.*;
import SSF.Net.*;
import SSF.OS.NetFlow.BytesUtil;
import SSF.Util.Streams.*;
import com.renesys.raceway.DML.*;
import com.renesys.raceway.SSF.*;
import java.text.*;
import java.util.LinkedList;
import SSF.OS.WWW.*;
/**
 * Used to monitor the requests received by a httpServer. 
 * It's similar to SSF.Net.droptailQueueMonitor, periodically probe the
 * number of requests received.
 * @author Yougu Yuan
 */
public class RequestsMonitor implements ProtocolMonitor {

    public static final String STREAM_TYPE = "RequestsMonitor";

    private java.text.DecimalFormat fm = new DecimalFormat();

    private long tickinterval;
    private boolean DEBUG=false;

    protected ProtocolSession owner=null;
    private ProbeSession P;
    private StreamInterface S;
    private int hostcode;
    private int typeCode;
    private double invfreq;
    private double intervalLength;

    /** total number of requests received by now. */
    private int requestCount=0;
    private int oldRequestCount=0;

    /** configure the Monitor. The supported DML attributes are:
     * <PRE>
     *   monitor [
     *     use SSF.OS.WWW.RequestsMonitor
     *     probe_interval  %F   # queue length averaging time interval, seconds (double)
     *     debug           %S   # print verbose diagnostics, true/false
     *   ]
     * </PRE>
     */
    public void config(ProtocolSession ownerProtocol, Configuration cfg) throws configException {
	owner = ownerProtocol;

	invfreq = 1.0/Net.frequency;

	String str = (String)cfg.findSingle("debug");
	if (str != null)
	    DEBUG = Boolean.valueOf(str).booleanValue();

	// format time output
	fm.setMinimumFractionDigits(3);
	fm.setMaximumFractionDigits(3);
   
	// interval between record transmission, in seconds
	str = (String)cfg.findSingle("probe_interval");
	if (str == null)
	    throw new configException(" RequestsMonitor: DML attribute monitor.probe_interval must be specified");
	else {
	    intervalLength = (new Double(str)).doubleValue();
	    tickinterval = Net.seconds(intervalLength);
	}

	if (DEBUG)
	    System.out.println("Configuring RequestsMonitor...\nprobe interval:"+intervalLength);
    }

    /** called by SSF.OS.WWW.httpServer.init()
     */
    public void init() {

	if (DEBUG)
	    System.out.println("init RequestsMonitor.");

	try {
	    P = (ProbeSession)(owner.inGraph().SessionForName("probe"));
	    S = P.getRecorder();
	    hostcode = P.getHostCode();
	    typeCode = S.getRecordTypeCode(STREAM_TYPE);

	    SSF.OS.Timer recordTimer = new SSF.OS.Timer(owner.inGraph(), 
							tickinterval) {
		    public void callback(){
			sendRecord();
			set(tickinterval);
		    }
		};

	    recordTimer.set();

	} catch (ProtocolException pex) {
	    System.err.println(" Can't configure RequestsMonitor: no ProbeSession registered in host");
	    System.err.println(pex.getMessage());
	    System.exit(1);
	}
    }

    private void sendRecord() {
	double time = invfreq*owner.inGraph().now();

	byte[] qRecord = new byte[BytesUtil.INT_LEN];

	BytesUtil.intToBytes(requestCount - oldRequestCount, qRecord, 0);

	if (DEBUG)
	    System.out.println("requestMonitor: " + fm.format(time)
			       + " requests " + requestCount);

	S.send(typeCode, hostcode, time, qRecord, 0, qRecord.length);
	oldRequestCount = requestCount;
    }

    /** Just increase a counter */
    public void receive(ProtocolMessage msg, ProtocolSession fromSession, ProtocolSession toSession) 
    {
	requestCount++;
    }

    public static String recordToString(byte[] bytes, int offset)
    {
	return "requests received: "+BytesUtil.bytesToInt(bytes, offset);
    }
}


